﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;
using System.Reflection;

namespace UpdateControllers
{
    public class AutoUpdateService
    {
        public string UpdateRoot = "";
        public event OnFileDownLoadHandler OnBeginUpdateComponent;
        public event OnFileDownLoadHandler OnStartUpdate;
        public event OnFileDownLoadHandler OnUpdatedComponentPart;
        public event OnFileDownLoadHandler OnUpdatedComponent;
        public event OnFileDownLoadHandler OnUpdateError;
        public event OnFileDownLoadHandler OnFinishUpdate;
        public event EventHandler OnConnectError;
        UpdateServices.UpdateServiceClient wService;
        public void CheckAllUpdate()
        {
            try
            {
                wService = new UpdateControllers.UpdateServices.UpdateServiceClient();
                //Download list of files
                DataSet ds = null;

                try
                {
                    ds=wService.GetAllUpdateableComponents();
                }
                catch
                {
                    if (OnConnectError != null)
                    {
                        OnConnectError(this,new EventArgs());
                    }
                    return;
                }
                if (ds == null) return;
                DataSet dsUpdated = GetUpdatedComponents();
                DataTable tblUpdated = dsUpdated.Tables[0];
                DataTable tblNew = ds.Tables[0];
                List<string> lsUpdateComponents = new List<string>();
                //Check list of files to update
                foreach (DataRow row in tblNew.Rows)
                {
                    DataRow[] rs = tblUpdated.Select("Path='" + row["Path"].ToString() + "'");
                    if (rs.Length > 0)
                    {
                        string fileName = GetPath().TrimEnd('\\') + "\\" + row["Path"].ToString().Replace("/", "\\");
                        if (int.Parse(rs[0]["Version"].ToString()) >= int.Parse(row["Version"].ToString()) && File.Exists(fileName))
                        {
                            continue;
                        }
                        else
                        {
                            lsUpdateComponents.Add(row["Path"].ToString());
                        }
                    }
                    else
                    {
                        lsUpdateComponents.Add(row["Path"].ToString());
                    }
                }
                //Updating
                if (OnStartUpdate != null)
                    OnStartUpdate(lsUpdateComponents, lsUpdateComponents.Count);
                int count = 0;
                foreach (string st in lsUpdateComponents)
                {
                    if (UpdateOneComponents(st))
                    {
                        //Add Log
                        DataRow row = tblNew.Select("Path='" + st + "'")[0];
                        DataRow[] rs = tblUpdated.Select("Path='" + st + "'");
                        if (rs.Length > 0)
                        {
                            rs[0]["Version"] = row["Version"];
                        }
                        else
                        {
                            DataRow r = tblUpdated.NewRow();
                            r["Path"] = st;
                            r["Version"] = row["Version"];
                            r["UpdatedDate"] = DateTime.Now;
                            tblUpdated.Rows.Add(r);
                        }
                        if (OnUpdatedComponent != null)
                            OnUpdatedComponent(st, count);
                    }
                    else
                    {
                        if (OnUpdateError != null)
                        {
                            OnUpdateError(st, count);
                        }
                    }

                    count++;
                }
                string logName = GetPath() + "\\LogUpdate.xml";
                dsUpdated.WriteXml(logName, XmlWriteMode.WriteSchema);
                if (OnFinishUpdate != null)
                    OnFinishUpdate(lsUpdateComponents, lsUpdateComponents.Count);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
        private bool UpdateOneComponents(string stName)
        {
            int count = wService.GetPacketCount(stName);
            if (OnBeginUpdateComponent != null)
            {
                OnBeginUpdateComponent(stName, count);
            }
            bool result = true;
            string fileName = GetPath().TrimEnd('\\') + "\\" + stName.Replace("/", "\\");
            string filePath = Path.GetDirectoryName(fileName);
            if (!Directory.Exists(filePath))
            {
                Directory.CreateDirectory(filePath);
            }
            if (File.Exists(fileName))
            {
                if (File.Exists(fileName + ".tmp"))
                    File.Delete(fileName + ".tmp");
                File.Move(fileName, fileName + ".tmp");
            }
            byte[] buff;
            FileStream strmFile = File.Create(fileName);
            for (int i = 0; i < count; i++)
            {
                try
                {
                    buff = wService.GetComponents(i, stName);
                    if (OnUpdatedComponentPart != null)
                    {
                        OnUpdatedComponentPart(stName, i);
                    }
                    if (buff.Length > 0)
                    {
                        strmFile.Write(buff, 0, buff.Length);
                    }
                    else
                    {
                        break;
                    }
                    System.Threading.Thread.Sleep(5);
                }
                catch
                {
                    try
                    {
                        strmFile.Close();
                        File.Delete(filePath);
                    }
                    catch
                    {
                    }
                    result = false;
                    break;
                }
            }
            if (result)
            {
                strmFile.Close();
                if (File.Exists(fileName + ".tmp"))
                {
                    File.Delete(fileName + ".tmp");
                }
            }
            else
            {
                //Error RollBack
                if (File.Exists(fileName + ".tmp"))
                {
                    File.Move(fileName + ".tmp", fileName);
                }
            }
            return result;
        }
        const int PACK_SIZE = 51200;
        private string GetPath()
        {
            return UpdateRoot;
        }
        private DataSet GetUpdatedComponents()
        {
            DataSet ds = new DataSet();
            string fileName = GetPath() + "\\LogUpdate.xml";
            if (File.Exists(fileName))
            {
                ds.ReadXml(fileName, XmlReadMode.ReadSchema);
            }
            else
            {
                ds.Tables.Add();
                ds.Tables[0].Columns.Add("Path", typeof(string));
                ds.Tables[0].Columns.Add("Version", typeof(int));
                ds.Tables[0].Columns.Add("UpdatedDate", typeof(DateTime));
            }
            return ds;
        }
    }
    public delegate void OnFileDownLoadHandler(object FileName, int Count);
}
